package qc.module.iot.api;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
import qc.common.core.utils.RadixConvertUtil;
import qc.module.iot.protocol.IotFrameBodyDataItem;
import qc.module.iot.protocol.IotFrameParseBase;
import qc.module.iot.protocol.IotFrameParseResult;
import qc.module.iot.protocol.custom.Custom_DeHongSwj_FrameParse;

import java.util.List;

/**
 * Iot报文接收微服务，接收原始报文后发送报文消息至MQ（如发送不成功直接写入数据库表）
 *
 * @author QuCheng Tech
 * @since 2025/10/28
 */
@SpringBootApplication
@ComponentScan({"qc.common.core"})//需要对qc.common.core封装的进行扫描，aspect中有数据库查询的selectOne添加limit 1
@MapperScan("qc.module.iot.repository")//不扫描repository在service中找不到对应的repository
@ComponentScan({"qc.module.iot.service"})//不扫描service在controller中找不到对应的service
@ComponentScan({"qc.module.iot.api.controller"})//不扫描controller从gateway找不到对应的微服务
//@EnableScheduling//启用定时任务
public class IotApiApplication {
    private static final Logger logger = LoggerFactory.getLogger(IotApiApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(IotApiApplication.class, args);

        //开发测试方法
        //debugTest();
    }

    @Bean
    @LoadBalanced // 开启负载均衡 Ribbon, 发送的请求都会被Ribbon拦截。必须使用应用名代替ip，否则报错
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    static void debugTest() {
        String hexString;
        String removeBlankString;
        byte[] bytes;
        //IotFrameParseBase dataFrameParse = new SL651_Hex_FrameParse();
        //IotFrameParseBase dataFrameParse = new SL651_Ascii_FrameParse();
        //IotFrameParseBase dataFrameParse = new SL427_FrameParse();
        //IotFrameParseBase dataFrameParse = new Modbus_Lj_Ems_FrameParse();
        IotFrameParseBase dataFrameParse = new Custom_DeHongSwj_FrameParse();

        //进制转换
        //hexString = "30303432";
        //bytes = RadixConvertUtil.hexStringToBytes(hexString);
        //String string = RadixConvertUtil.toAsciiString(bytes);
        //int intValue = RadixConvertUtil.hexStringToIntValue(string);
        //logger.debug("hexString:" + hexString + " intValue:" + intValue + " string:" + string);
        //hexString = "0000";
        //bytes = RadixConvertUtil.hexStringToBytes(hexString);
        //int intValue = RadixConvertUtil.hexStringToIntValue(hexString);
        //logger.debug("hexString:" + hexString + " intValue:" + intValue);

        //SL651 Hex 报文字符串
        /**
         * 上行报文：7E7E010004370301A000320021025B21251110133010F1F1000437030148F0F025111013303923000156753812117803EB34
         * 正文长度[33]，中心站地址[01]，遥测站地址[0004370301]，密码[A000]，功能码[32]，帧名称[遥测站定时报]，帧类型[数据包]，正文内容[5B21251110133010F1F1000437030148F0F0251110133039230001567538121178]
         * '0004370301','2025-11-10 13:30:00','ADC9','Z','00015.675','m','ADC20','VT','11.78','V'
         * 下行报文：7E7E000437030101A000328008025B21251110133010031D4A
         */
        /**
         * 上行报文：7E7E01008010380012342F000802015025111000000203E8EB
         * 正文长度[8]，中心站地址[01]，遥测站地址[0080103800]，密码[1234]，功能码[2F]，帧名称[链路维持报]，帧类型[心跳包]，正文内容[0150251110000002]
         * 上行报文：7E7E01008010380012342F000802015125111000004003841A
         * 正文长度[8]，中心站地址[01]，遥测站地址[0080103800]，密码[1234]，功能码[2F]，帧名称[链路维持报]，帧类型[心跳包]，正文内容[0151251110000040]
         */
        /**
         * 上行报文：7E7E0100801038001234320021020120251110000004F1F1008010380048F0F025111000003923000179303812128403556D
         * 正文长度[33]，中心站地址[01]，遥测站地址[0080103800]，密码[1234]，功能码[32]，帧名称[遥测站定时报]，帧类型[数据包]，正文内容[0120251110000004F1F1008010380048F0F0251110000039230001793038121284]
         * 遥测站地址：80103800、时间：251110、电压：12.84、水位：17.93
         */
        //正文长度[33]，中心站地址[01]，遥测站地址[0000000001]，密码[A000]，功能码[32]，帧名称[遥测站定时报]，帧类型[数据包]，正文内容[013A240516153010F1F1000000000148F0F0240516153039230001051038121343]
        //hexString = "7E7E 01 0000000001 A000 32 0021 02 013A240516153010F1F1000000000148F0F0240516153039230001051038121343 03 00C1";
        //类型：状态，名称：流水号，值：314，编码：sn
        //类型：发报时间，名称：发报时间，值：2024-05-16T15:30:10，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：0000000001，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：河道，编码：sttype
        //类型：数据时标，名称：时标，值：2024-05-16T15:30，编码：tm
        //类型：数据值，名称：Z，值：10.51，编码：Z
        //类型：数据值，名称：VT，值：13.43，编码：VT
        //hexString = "7E7E015301271224A00032002B02000C251114151010F1F1530127122448F0F02511141510201900000026190000003923FFFFFFFF3812122603455F";
        //类型：状态，名称：流水号，值：12，编码：sn
        //类型：发报时间，名称：发报时间，值：2025-11-14T15:10:10，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：5301271224，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：河道，编码：sttype
        //类型：数据时标，名称：时标，值：2025-11-14T15:10，编码：tm
        //类型：数据值，名称：PJ，值：0.0，编码：PJ
        //类型：数据值，名称：PT，值：0.0，编码：PT
        //类型：数据值，名称：Z，值：-，编码：Z
        //类型：数据值，名称：VT，值：12.26，编码：VT
        //hexString = "7E7E0100801038001234320021020120251110000004F1F1008010380048F0F025111000003923000179303812128403556D";

        //龙江项目中从德宏水文分局接入的雨量站数据，基本格式按SL651 Hex协议
        //hexString = "7E7E0100000005181234340038020019250414000001F1F1000000051848F0F02504132305F4600000000000000000000000001A19000000201900001526190033903812133303DA60";
        //帧类型[数据包]，帧名称[遥测站小时报]，报文[7E7E0100000005181234340038020019250414000001F1F1000000051848F0F02504132305F4600000000000000000000000001A19000000201900001526190033903812133303DA60]，完整数据帧报文[7E7E0100000005181234340038020019250414000001F1F1000000051848F0F02504132305F4600000000000000000000000001A19000000201900001526190033903812133303DA60]
        //类型：状态，名称：流水号，值：25，编码：sn
        //类型：发报时间，名称：发报时间，值：2025-04-14T00:00:01，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：0000000518，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：河道，编码：sttype
        //类型：数据时标，名称：时标，值：2025-04-13T23:05，编码：tm
        //类型：数据值，名称：备用，值：0，编码：F460
        //类型：数据值，名称：备用，值：0，编码：0000
        //类型：数据值，名称：备用，值：0，编码：0000
        //类型：数据值，名称：备用，值：2019，编码：0000
        //类型：数据值，名称：备用，值：20，编码：0000
        //类型：数据值，名称：备用，值：15，编码：1900
        //类型：数据值，名称：PT，值：339.0，编码：PT
        //类型：数据值，名称：VT，值：13.33，编码：VT


        //SL651 Ascii 报文字符串
        /**
         * 上行报文：0130313030303030303030303130343531333330303434023036383332353131313031303430313253542030303030303030303031204B2054542032353131313031303430205A3120312E363530205A204D2056542031312E3435200332303944
         * 正文长度[68]，中心站地址[01]，遥测站地址[0000000001]，密码[0451]，功能码[33]，帧名称[遥测站加报报]，帧类型[数据包]，正文内容[0683251110104012ST 0000000001 K TT 2511101040 Z1 1.650 Z M VT 11.45 ]
         * 下行报文：0130303030303030303031303130343531333380080230363833323531310356B1
         */
        //hexString = "01 30 31 30 30 30 30 30 30 30 30 31 33 39 39 39 39 33 33 30 30 34 32 02 30 33 42 37 31 38 30 36 32 32 31 36 33 35 30 30 53 54 20 30 30 30 30 30 30 30 30 31 33 20 4B 20 54 54 20 31 38 30 36 32 32 31 36 33 35 20 5A 55 20 38 36 37 2E 33 38 30 20 56 54 20 31 34 2E 32 35 20 03 37 31 34 41";
        //正文长度[66]，中心站地址[01]，遥测站地址[0000000013]，密码[9999]，功能码[33]，帧名称[遥测站加报报]，帧类型[数据包]，正文内容[03B7180622163500ST 0000000013 K TT 1806221635 ZU 867.380 VT 14.25 ]
        //类型：状态，名称：流水号，值：03B7，编码：sn
        //类型：发报时间，名称：发报时间，值：2018-06-22T16:35，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：0000000013，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：K，编码：sttype
        //类型：数据时标，名称：时标，值：2018-06-22T16:35，编码：tm
        //类型：数据值，名称：ZU，值：867.38，编码：ZU
        //类型：数据值，名称：VT，值：14.25，编码：VT
        //hexString = "01 30 31 30 30 30 30 30 30 30 30 30 31 30 34 35 31 33 33 30 30 34 34 02 30 36 38 33 32 35 31 31 31 30 31 30 34 30 31 32 53 54 20 30 30 30 30 30 30 30 30 30 31 20 4B 20 54 54 20 32 35 31 31 31 30 31 30 34 30 20 5A 31 20 31 2E 36 35 30 20 5A 20 4D 20 56 54 20 31 31 2E 34 35 20 03 32 30 39 44 ";
        //正文长度[68]，中心站地址[01]，遥测站地址[0000000001]，密码[0451]，功能码[33]，帧名称[遥测站加报报]，帧类型[数据包]，正文内容[0683251110104012ST 0000000001 K TT 2511101040 Z1 1.650 Z M VT 11.45 ]
        //类型：状态，名称：流水号，值：0683，编码：sn
        //类型：发报时间，名称：发报时间，值：2025-11-10T10:40:12，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：0000000001，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：K，编码：sttype
        //类型：数据时标，名称：时标，值：2025-11-10T10:40，编码：tm
        //类型：数据值，名称：Z1，值：1.65，编码：Z1
        //类型：数据值，名称：Z，值：M，编码：Z
        //类型：数据值，名称：VT，值：11.45，编码：VT
        //hexString = "0130313030303030303030303130343531333330303434023030313232353131313531313435313453542030303030303030303031204B2054542032353131313531313435205A3120312E303230205A204D2056542031322E3530200334373430";
        //正文长度[68]，中心站地址[01]，遥测站地址[0000000001]，密码[0451]，功能码[33]，帧名称[遥测站加报报]，帧类型[数据包]，正文内容[0012251115114514ST 0000000001 K TT 2511151145 Z1 1.020 Z M VT 12.50 ]
        //类型：状态，名称：流水号，值：0012，编码：sn
        //类型：发报时间，名称：发报时间，值：2025-11-15T11:45:14，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：0000000001，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：K，编码：sttype
        //类型：数据时标，名称：时标，值：2025-11-15T11:45，编码：tm
        //类型：数据值，名称：Z1，值：1.02，编码：Z1
        //类型：数据值，名称：Z，值：M，编码：Z
        //类型：数据值，名称：VT，值：12.5，编码：VT

        //SL427 报文字符串
        //hexString = "68 26 68 B3 0012340098 C0 07000000000010000000310100000000800000000000010036001205042500 DF 16";
        //类型：时标，名称：时标，值：2025-04-05T12:00:36，编码：tm
        //类型：数据值，名称：流量/水量1，值：0.007，编码：flow1
        //类型：数据值，名称：流量/水量1，值：1000，编码：sumwater1
        //类型：数据值，名称：流量/水量2，值：0.131，编码：flow2
        //类型：数据值，名称：流量/水量2，值：8000，编码：sumwater2
        //hexString = "681C68b33200100110c0AAAAAAAAAA050100000000002000000010300322001216";
        //类型：时标，名称：时标，值：2022-03-30T10:00，编码：tm
        //类型：数据值，名称：流量/水量，值：105，编码：sumwater
        //西山区长坡水位报文：
        //hexString = "68 1C 68 B3 53 01 12 14 00 C0 AA AA AA AA AA 75 13 82 01 00 01 00 70 00 10 00 22 19 11 25 0A 71 16";
        //正文长度[28]，中心站地址[null]，遥测站地址[5301121400]，密码[null]，功能码[C0]，帧名称[自报实时数据]，帧类型[数据包]，正文内容[AAAAAAAAAA7513820100010070001000221911250A]
        //类型：数据时标，名称：时标，值：2025-11-19T22:00:10，编码：tm
        //类型：数据值，名称：流量/水量，值：1821375，编码：sumwater

        //龙江使用的EMS系统发送至水情的机组闸门数据帧协议，基本结构按照Modbus协议
        //hexString = "01031A00090000FFFE0000001A0000000000000000000000000353032AB63C";
        //正文长度[26]，中心站地址[null]，遥测站地址[01]，密码[null]，功能码[03]，帧名称[数据包]，帧类型[数据包]，正文内容[00090000FFFE0000001A0000000000000000000000000353032A]
        //类型：数据值，名称：1，值：9，编码：1
        //类型：数据值，名称：2，值：0，编码：2
        //类型：数据值，名称：3，值：65534，编码：3
        //类型：数据值，名称：4，值：0，编码：4
        //类型：数据值，名称：5，值：26，编码：5
        //类型：数据值，名称：6，值：0，编码：6
        //类型：数据值，名称：7，值：0，编码：7
        //类型：数据值，名称：8，值：0，编码：8
        //类型：数据值，名称：9，值：0，编码：9
        //类型：数据值，名称：10，值：0，编码：10
        //类型：数据值，名称：11，值：0，编码：11
        //类型：数据值，名称：12，值：851，编码：12
        //类型：数据值，名称：13，值：810，编码：13

        //德宏水文局发送数据
        //hexString = "BEBE40000051010125041417001117111711171117111711171117111711171117111711171117";
        //正文长度[26]，中心站地址[null]，遥测站地址[40000051]，密码[null]，功能码[null]，帧名称[数据包]，帧类型[数据包]，正文内容[1117111711171117111711171117111711171117111711171117]
        //类型：数据值，名称：雨量，值：558.5，编码：rain
        hexString = "7E7E010040000500000034005502FE79250414170045F1F1004000050048F0F02504141605F460000000000000000000000000F5C002DF02E002DF02E002E002E002E002E002E002E002E002E0F0F0250414170026190566903923000073603812142503E6C4";
        //正文长度[85]，中心站地址[01]，遥测站地址[0040000500]，密码[0000]，功能码[34]，帧名称[遥测站小时报]，帧类型[数据包]，正文内容[FE79250414170045F1F1004000050048F0F02504141605F460000000000000000000000000F5C002DF02E002DF02E002E002E002E002E002E002E002E002E0F0F02504141700261905669039230000736038121425]
        //类型：状态，名称：流水号，值：65145，编码：sn
        //类型：发报时间，名称：发报时间，值：2025-04-14T17:00:45，编码：sendtm
        //类型：遥测站地址，名称：测站地址，值：0040000500，编码：stcd
        //类型：遥测站分类，名称：测站分类，值：河道，编码：sttype
        //类型：数据时标，名称：时标，值：2025-04-14T16:05，编码：tm
        //类型：数据值，名称：备用，值：0，编码：F460
        //类型：数据值，名称：备用，值：0，编码：0000
        //类型：数据值，名称：备用，值：0，编码：0000
        //类型：数据值，名称：备用，值：15620，编码：0000
        //类型：数据值，名称：备用，值：340，编码：02DF
        //类型：数据值，名称：备用，值：340，编码：02DF
        //类型：数据值，名称：备用，值：340，编码：02E0
        //类型：数据值，名称：备用，值：340，编码：02E0
        //类型：数据值，名称：备用，值：340，编码：02E0
        //类型：数据值，名称：备用，值：340，编码：02E0
        //类型：数据时标，名称：TT，值：2025-04-14T17:00，编码：TT
        //类型：数据值，名称：PT，值：5669.0，编码：PT
        //类型：数据值，名称：Z，值：7.36，编码：Z
        //类型：数据值，名称：VT，值：14.25，编码：VT

        //十六进制字符串去空格，转换为byte数组处理
        removeBlankString = StringUtils.deleteWhitespace(hexString);
        logger.debug("hex:" + removeBlankString);
        bytes = RadixConvertUtil.hexStringToBytes(hexString);

        IotFrameParseResult frameParseResult = dataFrameParse.parse(bytes, true);
        if (frameParseResult.isParseSuccess() == false) {
            logger.debug("解析数据帧失败，报文[{}]，解析错误信息[{}]", RadixConvertUtil.toHexString(bytes), frameParseResult.getParseErrorMsg());
        } else {
            logger.debug("解析数据帧成功，帧类型[{}]，帧名称[{}]，报文[{}]，完整数据帧报文[{}]", frameParseResult.getFrameType(),
                    frameParseResult.getFrameName(), RadixConvertUtil.toHexString(bytes), RadixConvertUtil.toHexString(frameParseResult.getParseFrameBytes()));
            //显示解析出的正文数据
            List<IotFrameBodyDataItem> bodyDataItems = frameParseResult.getBodyDataItems();
            if (bodyDataItems != null && bodyDataItems.size() > 0x0) {
                logger.debug("解析数据帧成功，共有正文内容项" + bodyDataItems.size() + "个。");
                for (IotFrameBodyDataItem item : bodyDataItems) {
                    logger.debug("类型：" + item.getType() + "，名称：" + item.getName() + "，值：" + item.getValue().toString() + "，编码：" + item.getCode());
                }
            } else {
                logger.debug("解析数据帧成功，没有正文内容项。");
            }
        }
    }
}
